home *** CD-ROM | disk | FTP | other *** search
/ PsL Monthly 1993 December / PSL Monthly Shareware CD-ROM (December 1993).iso / prgmming / dos / c / rcs.exe / CACHE.C < prev    next >
C/C++ Source or Header  |  1992-05-22  |  4KB  |  150 lines

  1. #include "cache.h"
  2. #include <alloc.h>
  3. #include <mem.h>
  4.  
  5. enum buffer_status {EMPTY, CLEAN, DIRTY};
  6.  
  7. static unsigned access(struct cache *q, int write, struct cache_block *b)
  8. {
  9.   unsigned e = (*q->drive_access)(write, b->drive, b->sector, b->data);
  10.   if (e!=0)
  11.   {
  12.     q->error_sector = b->sector;
  13.     q->error_drive = b->drive;
  14.   }
  15.   return e;
  16. }
  17.  
  18. unsigned cache_access(struct cache *q, int write, unsigned drive,
  19.   unsigned sector, void *buffer)
  20. {
  21.   struct
  22.   {
  23.     struct cache_block *previous;
  24.     struct cache_block *current;
  25.   } b, empty, clean, dirty;
  26.   /* find the matching block, and also the first empty, clean and dirty  */
  27.   /* blocks, all with a single pass through the list                     */
  28.   b.previous = empty.current = clean.current = dirty.current = NULL;
  29.   b.current = q->first;
  30.   do
  31.   {
  32.     if (b.current->status == EMPTY)
  33.     {
  34.       if (empty.current == NULL) empty = b;
  35.     }
  36.     else if (b.current->sector == sector && b.current->drive == drive)
  37.       break;
  38.     else
  39.     {
  40.       if (b.current->status == CLEAN)
  41.       {
  42.         if (clean.current == NULL) clean = b;
  43.       }
  44.       else if (dirty.current == NULL) dirty = b;
  45.     }
  46.     b.previous = b.current;
  47.     b.current = b.current->next;
  48.   } while (b.current != NULL);
  49.   /* if there is no matching block, assign one according to the rules */
  50.   if (b.current == NULL)
  51.   {
  52.     if (empty.current != NULL) b = empty;
  53.     else if (clean.current != NULL) b = clean;
  54.     else
  55.     {
  56.       unsigned e;
  57.       b = dirty;
  58.       e = access(q, 1, b.current);
  59.       if (e) return e;
  60.     }
  61.     b.current->status = EMPTY;
  62.     b.current->sector = sector;
  63.     b.current->drive = drive;
  64.   }
  65.   if (write)
  66.   {
  67.     memcpy(b.current->data, buffer, q->sector_size);
  68.     b.current->status = DIRTY;
  69.   }
  70.   else 
  71.   {
  72.     if (b.current->status == EMPTY)
  73.     {
  74.       unsigned e = access(q, 0, b.current);
  75.       if (e) return e;
  76.       b.current->status = CLEAN;
  77.     }
  78.     memcpy(buffer, b.current->data, q->sector_size);
  79.   }
  80.   /* put block at the end of the line */
  81.   if (b.current != q->last)
  82.   {
  83.     if (b.previous == NULL) q->first = b.current->next;
  84.     else b.previous->next = b.current->next;
  85.     q->last->next = b.current;
  86.     b.current->next = NULL;
  87.     q->last = b.current;
  88.   }
  89.   return 0;
  90. }
  91.  
  92. unsigned cache_flush_and_or_clear(struct cache *q, int drive, int options)
  93. {
  94.   struct cache_block *b;
  95.   for (b=q->first; b!=NULL; b=b->next)
  96.   {
  97.     if (drive<0 || b->drive==drive)
  98.     {
  99.       if (options&CACHE_FLUSH && b->status==DIRTY)
  100.       {
  101.         unsigned e = access(q, 1, b);
  102.         if (e) return e;
  103.         b->status = CLEAN;
  104.       }
  105.       if (options&CACHE_CLEAR) b->status = EMPTY;
  106.     }
  107.   }
  108.   return 0;
  109. }
  110.  
  111. void cache_free(struct cache *q)
  112. {
  113.   struct cache_block *b = q->first;
  114.   while (b!=NULL)
  115.   {
  116.     struct cache_block *next = b->next;
  117.     free(b);
  118.     b = next;
  119.   }
  120.   free(q);
  121. }
  122.  
  123. struct cache *cache_initialize(unsigned (*drive_access)(int, unsigned,
  124.   unsigned, void *), unsigned number_of_sectors, unsigned sector_size)
  125. {
  126.   struct cache *q = malloc(sizeof(struct cache));
  127.   if (q!=NULL)
  128.   {
  129.     struct cache_block *b;
  130.     b = q->first = malloc(sizeof(struct cache_block)+sector_size-1);
  131.     while (1)
  132.     {
  133.       if (b==NULL)
  134.       {
  135.         cache_free(q);
  136.         return NULL;
  137.       }
  138.       b->status = EMPTY;
  139.       if (--number_of_sectors == 0) break;
  140.       b = b->next = malloc(sizeof(struct cache_block)+sector_size-1);
  141.     }
  142.     b->next = NULL;
  143.     q->last = b;
  144.     q->drive_access = drive_access;
  145.     q->sector_size = sector_size;
  146.   }
  147.   return q;
  148. }
  149.  
  150.